package org.example.verify;

import org.example.csv.CSVData;
import org.example.util.CSVUtils;
import org.example.util.FileUtils;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Case1Verify {

    public static final String basicPath = "D:\\Development\\GeaFlowCompetition\\sf1\\snapshot";

    public static final String outputPath = "D:\\Development\\GeaFlowCompetition\\output";

    public static final String outputName = "result1-sf1-check.csv";

    Set<String> allNodes = new HashSet<>();

    Map<String, List<String>> personOwnAccountMap = new HashMap<>();

    Map<String, List<String>> accountDepositLoanMap = new HashMap<>();

    // in
    Map<String, List<String>> accountTransferAccountMap = new HashMap<>();

    Map<String, Double> loanAmountMap = new HashMap<>();

    Map<String, Double> resMap = new HashMap<>();

    Map<String, List<String>> checkLoanMap = new HashMap<>();

    public static void main(String[] args) {
        new Case1Verify().start();
    }

    public void start() {

        prepare();

        compute();

        writeToFile();
    }

    private void prepare() {
        /* ============================== person own account ============================== */
        Path personOwnAccount = FileUtils.pathJoin(basicPath, "PersonOwnAccount.csv");
        CSVData personOwnAccountData = CSVUtils.read(personOwnAccount);
        List<String> personIdList = personOwnAccountData.getByColumn("personId");
        List<String> accountIdList = personOwnAccountData.getByColumn("accountId");

        for (int i = 0; i < personIdList.size(); i++) {
            String person = personIdList.get(i);
            String account = accountIdList.get(i);
            List<String> personOwnAccountsList;
            if (personOwnAccountMap.containsKey(person)) {
                personOwnAccountsList = personOwnAccountMap.get(person);
                if (personOwnAccountsList.contains(account)) {
                    System.out.println("person owns same account");
                }
            } else {
                personOwnAccountsList = new ArrayList<>();
            }
            personOwnAccountsList.add(account);
            personOwnAccountMap.put(person, personOwnAccountsList);

            allNodes.add(person);
            if (allNodes.contains(account)) {
                System.out.println("all nodes check account exist");
            } else {
                allNodes.add(account);
            }
        }

        System.out.println("person size: " + personOwnAccountMap.size());

        /* ============================== account deposit loan ============================== */
        Path loanDepositAccount = FileUtils.pathJoin(basicPath, "LoanDepositAccount.csv");
        CSVData loanDepositAccountData = CSVUtils.read(loanDepositAccount);
        List<String> loanIdList = loanDepositAccountData.getByColumn("loanId");
        List<String> loanAccountIdList = loanDepositAccountData.getByColumn("accountId");

        for (int i = 0; i < loanIdList.size(); i++) {
            String loan = loanIdList.get(i);
            String loanAccount = loanAccountIdList.get(i);

            List<String> tmp;
            if (accountDepositLoanMap.containsKey(loanAccount)) {
                tmp = accountDepositLoanMap.get(loanAccount);
            } else {
                tmp = new ArrayList<>();
            }
            tmp.add(loan);
            accountDepositLoanMap.put(loanAccount, tmp);
        }

        System.out.println("account deposit loan size: " + accountDepositLoanMap.size());

        /* ============================== person own account ============================== */
        Path accountTransferAccount = FileUtils.pathJoin(basicPath, "AccountTransferAccount.csv");
        CSVData accountTransferAccountData = CSVUtils.read(accountTransferAccount);
        List<String> fromIdList = accountTransferAccountData.getByColumn("fromId");
        List<String> toIdList = accountTransferAccountData.getByColumn("toId");

        for (int i = 0; i < fromIdList.size(); i++) {
            String from = fromIdList.get(i);
            String to = toIdList.get(i);

            List<String> tmp;
            if (accountTransferAccountMap.containsKey(to)) {
                tmp = accountTransferAccountMap.get(to);
            } else {
                tmp = new ArrayList<>();
            }
            tmp.add(from);
            accountTransferAccountMap.put(to, tmp);
        }

        /* ============================== loan amount ============================== */
        Path loanAmount = FileUtils.pathJoin(basicPath, "Loan.csv");
        CSVData loanAmountData = CSVUtils.read(loanAmount);
        List<String> loanUniqueIdList = loanAmountData.getByColumn("loanId");
        List<String> loanAmountList = loanAmountData.getByColumn("loanAmount");

        for (int i = 0; i < loanUniqueIdList.size(); i++) {
            String uniqueId = loanUniqueIdList.get(i);
            String amount = loanAmountList.get(i);

            if (loanAmountMap.containsKey(uniqueId)) {
                System.out.println("loan has existed.");
            } else {
                double loanValue = Double.parseDouble(amount);
                if (loanValue == 0.0) {
                    System.out.println("loan == 0.0");
                }
                loanAmountMap.put(uniqueId, loanValue);
            }
        }
        System.out.println("loan entity size: " + loanUniqueIdList.size());
    }


    private void compute() {
        for (String person : personOwnAccountMap.keySet()) {
            List<String> tmp = new ArrayList<>();
            List<String> outAccounts = personOwnAccountMap.get(person);

            for (String subAccount : outAccounts) {
                if (!accountTransferAccountMap.containsKey(subAccount)) continue;
                List<String> otherAccountList = accountTransferAccountMap.get(subAccount);
                for (String item : otherAccountList) {
                    if (!accountDepositLoanMap.containsKey(item)) continue;
                    List<String> lst = accountDepositLoanMap.get(item);
                    tmp.addAll(lst);
                }
            }
            checkLoanMap.put(person, tmp);
        }

        for (String person : checkLoanMap.keySet()) {
            List<String> lst = checkLoanMap.get(person);
            Set<String> set = new HashSet<>(lst);

            double sum = 0.0;
            for (String item : set) {
                sum += loanAmountMap.get(item);
            }
            resMap.put(person, sum);
        }
    }

    private void writeToFile() {
        CSVData writer = new CSVData(Arrays.asList("id", "value"));
        List<Long> ids = new ArrayList<>();
        for (String key : resMap.keySet()) {
            if (resMap.get(key) != 0.0) {
                ids.add(Long.valueOf(key));
            }
        }
        Collections.sort(ids);
        for (Long id : ids) {
            String key = String.valueOf(id);
            double value = resMap.get(key);
            String sv = String.format("%.2f", value / 100_000_000);
            writer.addLine(new String[]{key, sv});
        }
        CSVUtils.write(FileUtils.pathJoin(outputPath, outputName), writer);
    }
}
